#ifndef MDICT_BASE_H
#define MDICT_BASE_H

#include <array>
#include <cstdint>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "BinaryIO.h"
#include "CompressionUtils.h"
#include "CryptoUtils.h"

using std::array;
using std::cout;
using std::endl;
using std::map;
using std::pair;
using std::string;
using std::vector;

struct MdictMeta {
    string GeneratedByEngineVersion;
    string RequiredEngineVersion;
    string Format;
    string Encrypted;
    string Description;
    string Title;
    string Encoding;
    string CreationDate;
    string StyleSheet;

    string encoding;
    uint8_t encrypt;
    map<string, pair<string, string>> stylesheet;
    float version;
    uint8_t number_width;
    // key block的开始位置
    uint32_t key_block_offset;
    // record block的开始位置
    uint32_t record_block_offset;
};

struct MdictHeader {
    // 头部字节数(大端)
    uint32_t header_bytes_size;
    // 头部元数据
    MdictMeta meta;
    vector<uint8_t> header_bytes;
    // 头部的校验和(小端)
    uint32_t adler32;

    map<string, string> parse_header(string text);
    MdictMeta metaData();
};

// =================================================key block
#pragma pack(push, 1)
struct KeyBlockHeaderV1 {
    // KeyBlock chunk数量
    uint32_t block_number;
    // key 的数量
    uint32_t key_number;
    // key block info 部分的字节数
    uint32_t info_bytes_size;
    // KeyBlock部分的字节数
    uint32_t block_bytes_size;
};
#pragma pack(pop)

struct KeyBlockHeader {
    // KeyBlock chunk数量
    uint64_t chunks_num;
    // key 的数量
    uint64_t key_num;
    // key block info 部分解压后的字节数（version>=2)
    uint64_t info_decompress_bytes_size;
    // key block info 部分的字节数
    uint64_t info_bytes_size;
    // KeyBlock chunks区域的总的字节数
    uint64_t chunks_bytes_size;
    // 上面5个字节的checksum
    uint32_t adler32;
};

struct KeyBlockInfoChunk {
    uint64_t key_num;
    uint16_t head_bytes_size;
    // vector<header_bytes_size+1> head;
    uint16_t tail_bytes_size;
    // vector<tail_bytes_size+1> tail;
    uint64_t compressed_size;
    uint64_t decompressed_size;
};

struct KeyBlockInfo {
    uint32_t header = 0x02;
    // chunks部分的校验和
    uint32_t adler32;
    // encrypt == 0x02时：先将4-8这四个字节使用ripemd128进行变换
    // 成一个key，然后再通过fast解密
    vector<KeyBlockInfoChunk> chunks;

    vector<pair<uint32_t, uint32_t>> decode_key_block_info();
};
struct KeyBlockChunk {};

// struct KeyBlock {
//     KeyBlockHeader header;
//     KeyBlockInfo info;
//     vector<KeyBlockChunk> chunks;
// };

// =================================================record block
struct RecordBlockHeader {};
struct RecordBlockInfo {};
struct RecordBlockChunk {};

struct RecordBlock {
    RecordBlockHeader header;
    RecordBlockInfo info;
    vector<RecordBlockChunk> chunks;
};

// =================================================mdx
struct mdx {
    MdictHeader header;
    // KeyBlock key_block;
    RecordBlock record_block;

private:
    string m_filename;
    float m_version;
    int m_number_width;
    uint8_t m_encrypt;
    string m_encoding;
    string m_number_format;
    void readHeader();

public:
    mdx(const string& file);
};

// =================================================mdd
struct mdd {};

struct Record {
    uint64_t offset;
    uint32_t size;
};

struct KeyBlockIndex {
    string first_key;
    string last_key;
    uint64_t compressed_size;
    uint64_t decompressed_size;
};

struct KeyIndex {
    string key;
    uint64_t offset_for_record_block;
    int64_t entryNum;
};

struct KeyBlock {
    KeyBlockIndex key_block_index;
    vector<KeyIndex> key_indexs;
};

class MDictBase {
protected:
    string m_filename;
    string m_encoding;
    uint8_t* m_encrypted_key = nullptr;
    float m_version;
    int m_num_entries;
    int m_encrypt;
    map<string, pair<string, string>> m_stylesheet;
    int m_number_width;
    string m_number_format;

    // 文件偏移量
    long m_key_block_offset;
    long m_record_block_offset;

    // v3特有偏移量
    long m_key_index_offset;
    long m_key_data_offset;
    long m_record_index_offset;

    vector<pair<uint64_t, string>> m_key_list;
    vector<KeyBlockIndex> m_key_block_indexs;
    map<string, Record> m_key_offset;

    // 核心方法
    virtual map<string, string> _read_header();
    virtual vector<pair<uint64_t, string>> _read_keys();
    virtual vector<pair<string, vector<uint8_t>>> _read_records() = 0;
    virtual vector<uint8_t> _decode_block(const vector<uint8_t>& block,
                                          uint32_t decompressed_size);

    // 辅助方法
    // TODO:
    map<string, string> _parse_header(const string& header_text);
    vector<KeyIndex> _split_key_block(const vector<uint8_t>& block);
    vector<pair<uint64_t, string>> _read_keys_v1v2();
    // TODO:
    vector<pair<uint64_t, string>> _read_keys_v3();
    // TODO:
    vector<pair<uint64_t, string>> _read_keys_brutal();

private:
    vector<pair<uint64_t, uint64_t>> _decode_key_block_info(
        vector<uint8_t> key_block_info);
    vector<pair<uint64_t, string>> _decode_key_block(
        vector<uint8_t> key_block_compressed,
        vector<pair<uint64_t, uint64_t>> info_list);

public:
    MDictBase(const string& fname, const string& encoding = "",
              const pair<vector<uint8_t>, string>& passcode = {});
    virtual ~MDictBase();

    int size() const { return m_num_entries; }
    string encoding() { return m_encoding; }
    vector<string> keys() const;
    Record get_offset_and_size(const string& word);
    virtual vector<pair<string, vector<uint8_t>>> items() = 0;
};

#endif  // MDICT_BASE_H
